package tencent

import (
	"context"
	"fmt"

	// "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
	"github.com/ecodeclub/ekit" // 泛型工具包
	"github.com/ecodeclub/ekit/slice"
	sms "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms/v20210111" // 引入sms
)

type Service struct {
	client *sms.Client
	// 这里腾讯的sdk的设计为string的指针，
	// 我理解其是为了统一不传参数时，都为nil,
	// 可以看到sdk中不仅是string，其他的所有参数都是指针的方式
	// 但大明认为这不是一个好的设计，因为当使用一个nil对象的属性时，
	// 会panic，所以每次都要去判断是不是nil
	appId    *string
	signName *string
}

func (s *Service) Send(ctx context.Context, tplId string, args []string, numbers ...string) error {
	request := sms.NewSendSmsRequest()
	request.SetContext(ctx)
	request.SmsSdkAppId = s.appId
	request.SignName = s.signName
	request.TemplateId = ekit.ToPtr[string](tplId)
	request.TemplateParamSet = s.toPtrSlice(args)
	request.PhoneNumberSet = s.toPtrSlice(numbers)
	response, err := s.client.SendSms(request)
	// 处理异常
	if err != nil {
		fmt.Printf("An API error has returned: %s", err)
		return err
	}
	for _, statusPtr := range response.Response.SendStatusSet {
		// 这里就是大明认为sdk中什么都是指针的不太好的原因
		// 因为nil可能引发程序的panic，
		// sms作为外部的服务，我们肯定是要加判断的，
		// 否则就可能引发自己程序的panic
		if statusPtr == nil {
			continue
		}
		status := *statusPtr
		if status.Code == nil || *(status.Code) != "Ok" {
			// 发送失败
			return fmt.Errorf("发送短信失败 code: %s, msg: %s", *status.Code, *status.Message)
		}
	}
	return nil
}

func (s *Service) toPtrSlice(data []string) []*string {
	// 类似函数式编程中的map
	return slice.Map[string, *string](data,
		func(idx int, src string) *string {
			return &src
		})
}

func NewService(client *sms.Client, appId string, signName string) *Service {
	return &Service{
		client:   client,
		appId:    &appId,
		signName: &signName,
	}
}
